/*! 
  \file compress.c
  \brief Implementation of the main compression program in Parallel using the Nvidia CUDA platform.
*/

#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h> 

#include <utils.h>
#include <bwt.h>
#include <mtf.h>
#include <huff.h>

#define SIZE 131172 //128K = (16k per SMP/2 strings needed) * 16 SMPs

__global__ void bwt(unsigner char* A, unsigner char* B)
{
  int i, j;
  int index = threadIdx.y*N + threadIdx.x;
  int row = N*BLOCK_N*blockIdx.y + index;
  int col = BLOCK_N*blockIdx.x + index;
  float total = 0;

}

__global__ void mtf(unsigner char* A, unsigner char* B)
{
  int i, j;
  int index = threadIdx.y*N + threadIdx.x;
  int row = N*BLOCK_N*blockIdx.y + index;
  int col = BLOCK_N*blockIdx.x + index;
  float total = 0;

}

main(int argc, char* argv[])
{
  FILE *ifp, *ofp;
  char *input_file, *output_file;
  size_t bytes_read;
  int file_size, bwt_index, status;
  
  if (argc != 3) {
    printf("Usage: %s <input_file> <output_file>\n", argv[0]);
    exit(-1);
  }
  
  input_file = argv[1];
  output_file = argv[2];
  
  if (open_file(input_file, "r", &ifp, 1) == -1)
    exit(-1);
    
  if (open_file(output_file, "w", &ofp, 0) == -1)
    exit(-1);

  struct stat *buf = malloc(sizeof(struct stat));
  lstat(input_file, buf);
  int size = buf->st_size;

  unsigner char* A = malloc(size);
  unsigner char* B = malloc(size);
  unsigner char* X,* Y;

  while (!feof(ifp)) {
    memset(A, '\0', SIZE);
    bytes_read = fread(A, 1, SIZE, ifp);
  
    dim3 dimBlock(BLOCK_N, BLOCK_N);
    dim3 dimGrid(N/BLOCK_N, N/BLOCK_N);

    cudaMalloc((void**)&X, SIZE);
    cudaMalloc((void**)&Y, SIZE);

    if(cudaMemcpy(X, A, SIZE, cudaMemcpyHostToDevice)!=cudaSuccess)
      fprintf(stderr, "Copy from host to device failed\n");

    clock_gettime ( CLOCK_REALTIME, &start );

    bwt<<<dimGrid, dimBlock>>>(X, Y);
    //mtf<<<dimGrid, dimBlock>>>(Y, X);
    //huff<<<dimGrid, dimBlock>>>(X, Y);

    //compress<<<dimGrid, dimBlock>>>(X, Y);

    clock_gettime ( CLOCK_REALTIME, &end );

    cudaError_t meow;
    if((meow = cudaMemcpy(A, Y, size, cudaMemcpyDeviceToHost))!=cudaSuccess)
      fprintf(stderr, "Copy from device to host failed: %s\n", cudaGetErrorString(meow));
    if((meow = cudaMemcpy(B, X, size, cudaMemcpyDeviceToHost))!=cudaSuccess)
      fprintf(stderr, "Copy from device to host failed: %s\n", cudaGetErrorString(meow));

    fwrite(B, 1, i, ofp);
  }

  cudaFree(X);
  cudaFree(Y);

  fclose(ifp);
  fclose(ofp);

  double time = (end.tv_sec - start.tv_sec)*1000000000 + (end.tv_nsec - start.tv_nsec);
  
  printf("Compression completed in %f us\n", time/1000);

}
